import {
  Action,
  BoticordAbility,
  fromJwt,
  fromParam, fromResponse,
  InjectAbility,
  JwtPayload,
  JwtPayloadDto,
  PermissionsDecoratorOptions,
  PermissionsTo,
} from '@boticord/auth'
import { CreateReplyDto, CreateReviewDto, ResourceComment, UpdateReviewDto } from '@boticord/resources-client'
import { Body, Controller, Delete, Get, NotFoundException, Param, Patch, Post } from '@nestjs/common'
import { ErrorCodes } from '@boticord/consts'
import { AnalyseRequest, EventTypes } from '@boticord/analytics'
import { CommentsService } from '../services/comments.service'

const permissionsOptions: PermissionsDecoratorOptions<ResourceComment> = {
  fetch: {
    id: fromParam('comment'),
    exception: new NotFoundException({ code: ErrorCodes.UnknownComment }),
    options: {
      relations: {
        author: true,
      },
    },
  },
}

const replyPermissionsOptions: PermissionsDecoratorOptions<ResourceComment> = {
  fetch: {
    id: fromParam('comment'),
    exception: new NotFoundException({ code: ErrorCodes.UnknownComment }),
    options: {
      relations: [ 'resource', 'resource.moderators', 'resource.developers' ],
    },
  },
}

@Controller('comments')
export class CommentController {
  constructor(
    private readonly comments: CommentsService,
  ) {}

  /** get list of comments for a resource */
  @Get(':resource')
  @PermissionsTo(Action.ReadMany, ResourceComment, permissionsOptions)
  // @AnalyseRequest(EventTypes.CommentsViewed, analyticsOptions)
  async getComments(@Param('resource') discordID: string) {
    return this.comments.readAll(discordID)
  }

  /** create new comment for a resource */
  @Post(':resource')
  @PermissionsTo(Action.Create, ResourceComment)
  @AnalyseRequest(EventTypes.CommentAdded, {
    affected: fromParam('resource'),
    user: fromJwt('id'),
    extract: fromResponse('content', 'rating'),
  })
  async createComment(
    @Param('resource') resourceID: string,
    @Body() body: CreateReviewDto,
    @JwtPayload() payload: JwtPayloadDto,
    @InjectAbility() ability: BoticordAbility,
  ) {
    return this.comments.create(resourceID, body, ability, payload)
  }

  // wtf can't like comments
  // fuck likes, all my homies hate likes
  // likes are for normies!! boticord is too small to likes is present

  @Delete(':resource/:comment')
  @PermissionsTo(Action.Delete, ResourceComment, permissionsOptions)
  @AnalyseRequest(EventTypes.CommentRemoved, { 
    affected: fromParam('resource'), 
    user: fromJwt('id'), 
    extract: fromResponse('content', 'rating'),
  })
  async deleteComment(@Param('comment') commentID: string, @Param('resource') resourceID: string) {
    return this.comments.delete(commentID, resourceID)
  }

  @Patch(':resource/:comment')
  @PermissionsTo(Action.Modify, ResourceComment, permissionsOptions)
  @AnalyseRequest(EventTypes.CommentEdited, {
    affected: fromParam('resource'), 
    user: fromJwt('id'),
    extract: fromResponse('content', 'rating'),
  })
  async editComment(
    @Param('comment') commentID: string,
    @Param('resource') resourceID: string,
    @Body() dto: UpdateReviewDto,
    @InjectAbility() ability: BoticordAbility,
    @JwtPayload() payload: JwtPayloadDto,
  ) {
    return this.comments.update(commentID, dto, ability, payload)
  }

  @Post(':resource/:comment/reply')
  @PermissionsTo(Action.Reply, ResourceComment, replyPermissionsOptions)
  async replyComment(
    @Param('comment') commentID: string,
    @Body() dto: CreateReplyDto,
  ) {
    return this.comments.reply(commentID, dto.content)
  }

  @Patch(':resource/:comment/reply')
  @PermissionsTo(Action.Reply, ResourceComment, replyPermissionsOptions)
  async editReplyComment(
    @Param('comment') commentID: string,
    @Body() dto: CreateReplyDto,
  ) {
    return this.comments.editReply(commentID, dto.content)
  }

  @Delete(':resource/:comment/reply')
  @PermissionsTo(Action.Reply, ResourceComment, replyPermissionsOptions)
  async deleteReplyComment(
    @Param('comment') commentID: string,
  ) {
    return this.comments.deleteReply(commentID)
  }
}
